package com.example.xgakj.newterminal.ui.activities;

import android.content.res.Configuration;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.IdRes;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;

import com.example.xgakj.newterminal.R;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;

import butterknife.BindView;
import butterknife.ButterKnife;

public class VedioPlayActivity extends AppCompatActivity {
    @BindView(R.id.surfaceView)
    SurfaceView surfaceView;
    @BindView(R.id.pb)
    ProgressBar pb;
    @BindView(R.id.rb_1)
    RadioButton rb1;
    @BindView(R.id.rb_2)
    RadioButton rb2;
    @BindView(R.id.rb_4)
    RadioButton rb4;
    @BindView(R.id.radioGroup)
    RadioGroup radioGroup;
    @BindView(R.id.cbx_play)
    CheckBox cbxPlay;
    private File h264File;
    private InputStream is = null;
    private FileInputStream fs = null;
    DisplayMetrics dm;
    ViewGroup.LayoutParams lp;
    private MediaCodec mCodec;
    private int screenWidth;
    private int screenHeight;
    private WindowManager mWindowManager;
    private long timeInterval = 60;
    Thread readFileThread;
    boolean isInit = false;

    // Video Constants
    private final static String MIME_TYPE = "video/avc"; // H.264 Advanced Video
    private final static int VIDEO_WIDTH = 608;
    private final static int VIDEO_HEIGHT = 448;
    private final static int TIME_INTERNAL = 30;
    private final static int HEAD_OFFSET = 100;
    private boolean readFlag;
    private boolean isplaying;
    private WeakHandler weakHandler;
    private long length;
    private boolean isPausing;
    private boolean ignore;

    private static class WeakHandler extends Handler {
        WeakReference<VedioPlayActivity> weakReference;

        public WeakHandler(VedioPlayActivity activity) {
            weakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            VedioPlayActivity activity = weakReference.get();
            if (activity != null) {
                switch (msg.what) {
                    case 0:
                        int max = msg.arg1;
                        activity.setProgressBar(max);
                        break;
                    case 1:
                        int progress = msg.arg1;
                        activity.setPBProgress(progress);

                        break;
                    default:
                }
            }
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vedio_play);
        ButterKnife.bind(this);
        weakHandler = new WeakHandler(this);
        String path = getIntent().getStringExtra("path");
        h264File = new File(path);
        dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        lp = surfaceView.getLayoutParams();
        //根据横竖屏确定surface
        if (isScreenChange()){
            screenWidth = dm.heightPixels;
            screenHeight = dm.widthPixels;
        }else {
            screenWidth = dm.widthPixels;
            screenHeight = dm.heightPixels;
        }
        pb.setMax(100);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
                switch (checkedId) {
                    case R.id.rb_1:
                        timeInterval = 60;
                        break;
                    case R.id.rb_2:
                        timeInterval = 30;
                        break;
                    case R.id.rb_4:
                        timeInterval = 15;
                        break;
                    default:
                }

            }
        });
        cbxPlay.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                if (!ignore){
                    if (isChecked){
                        isPausing=true;
                    }else {
                        isPausing=false;
                    if (readFlag==false){
                        palyVideo();
                    }
                    }
                }

            }
        });
        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {

                palyVideo();

            }


            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                readFlag = false;
                stopDecoder();
            }
        });

    }

    private void palyVideo() {
        if (h264File.exists()) {
            length = h264File.length();

            if (!isInit) {
                initDecoder();
                isInit = true;
            }
            readFileThread = new Thread(readFile);
            readFileThread.start();
        } else {
            Toast.makeText(getApplicationContext(),
                    "视频不存在", Toast.LENGTH_SHORT).show();
        }
    }

    public void setProgressBar(int max) {
        pb.setMax(max);
    }

    public void setPBProgress(int progress) {
        pb.setProgress(progress);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        weakHandler.removeCallbacksAndMessages(null);

    }

    public void initDecoder() {

        try {
            mCodec = MediaCodec.createDecoderByType(MIME_TYPE);
        } catch (IOException e) {
            e.printStackTrace();
        }
        MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE,
                VIDEO_WIDTH, VIDEO_HEIGHT);
        mCodec.configure(mediaFormat, surfaceView.getHolder().getSurface(),
                null, 0);
        lp.width = screenWidth;
        float rate = (448 / (float) 608);
        lp.height = (int) (screenWidth * rate);

        surfaceView.setLayoutParams(lp);
        mCodec.start();
    }

    int mCount = 0;

    public boolean onFrame(byte[] buf, int offset, int length) {
        // Get input buffer index
        //查找sps
        if(!firstsps){
            if(buf[0]==0 && buf[1]==0 && buf[2]==0 && buf[3]==1 && buf[4]==103){
                firstsps = true;

            }else{
                return true;
            }
        }
        ByteBuffer[] inputBuffers = mCodec.getInputBuffers();
        int inputBufferIndex = mCodec.dequeueInputBuffer(100);

        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(buf, offset, length);
            mCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount
                    * TIME_INTERNAL, 0);
            mCount++;
        }else {
            return false;
        }

        // Get output buffer index
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 100);
        while (outputBufferIndex >= 0) {
            mCodec.releaseOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 0);
        }
        return true;
    }

    /**
     * Find H264 frame head
     *
     * @param buffer
     * @param len
     * @return the offset of frame head, return 0 if can not find one
     */
    static int findHead(byte[] buffer, int len) {
        int i;
        if (len<HEAD_OFFSET){
            return 0;
        }
        for (i = HEAD_OFFSET; i < len; i++) {
            if (checkHead(buffer, i)) {
                break;
            }
        }
        if (i == len){
            Log.e("shurun","找不到头");
            return 0;

        }

        if (i == HEAD_OFFSET){
            return 0;
        }

        return i;
    }

    /**
     * Check if is H264 frame head
     *
     * @param buffer
     * @param offset
     * @return whether the src buffer is frame head
     */
    static boolean checkHead(byte[] buffer, int offset) {
        // 00 00 00 01
        if (buffer[offset] == 0 && buffer[offset + 1] == 0
                && buffer[offset + 2] == 0 && buffer[3] == 1) {
            return true;
        }
        // 00 00 01
//        if (buffer[offset] == 0 && buffer[offset + 1] == 0
//                && buffer[offset + 2] == 1)
//            return true;
        return false;
    }


    private boolean firstsps;
    Runnable readFile = new Runnable() {

        @Override
        public void run() {
            int h264Read = 0;
            int frameOffset = 0;
            byte[] buffer = new byte[100000];
            byte[] framebuffer = new byte[200000];
            readFlag = true;
            try {
                fs = new FileInputStream(h264File);
                is = new BufferedInputStream(fs);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            while (!Thread.interrupted() && readFlag) {
                try {
                   int readlength = is.available();
                    if (readlength == 0) {
                        weakHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                readFlag = false;
//                                mCodec.flush();
                                ignore=true;
                                cbxPlay.setChecked(true);
                                ignore=false;
                            }
                        });
                        Message message3 = weakHandler.obtainMessage();
                        message3.what = 1;
                        message3.arg1 = 0;
                        weakHandler.sendMessage(message3);
                        break;
                    }
                    if (readlength > 0) {
                        // Read file and fill buffer
                        int count = is.read(buffer);
                        h264Read += count;
                        int readNum = (int) ((h264Read / (double) length) * 100);
                      /*  Message message2 = weakHandler.obtainMessage();
                        message2.what = 1;
                        message2.arg1 = readNum;
                        weakHandler.sendMessage(message2);*/

                        // Fill frameBuffer
                        if (frameOffset + count < 200000) {
                            System.arraycopy(buffer, 0, framebuffer,
                                    frameOffset, count);
                            frameOffset += count;
                        } else {
                            frameOffset = 0;
                            System.arraycopy(buffer, 0, framebuffer,
                                    frameOffset, count);
                            frameOffset += count;
                        }

                        // Find H264 head

                        int offset = findHead(framebuffer, frameOffset);


                        while (offset > 0 && readFlag) {

                            if (checkHead(framebuffer, 0)) {

                                boolean flag = onFrame(framebuffer, 0, offset);
                                while (isPausing){
                                    SystemClock.sleep(timeInterval*10);
                                }
                                SystemClock.sleep(timeInterval);
                                if (flag && readFlag) {
                                    byte[] temp = framebuffer;
                                    framebuffer = new byte[200000];

                                    System.arraycopy(temp, offset, framebuffer,
                                            0, frameOffset - offset);
                                    frameOffset -= offset;

                                    // Continue finding head
                                    offset = findHead(framebuffer, frameOffset);


                                }
                            } else {
                                offset = 0;
                            }

                        }
                        Message message2 = weakHandler.obtainMessage();
                        message2.what = 1;
                        message2.arg1 = readNum;
                        weakHandler.sendMessage(message2);
                        Log.d("loop", "end loop");
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
            try {
            if (is!=null){
                    is.close();
                is=null;
                }
                if (fs!=null){
                    fs.close();
                    fs=null;
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    };


    public void stopDecoder() {
        if (mCodec != null) {
            mCodec.flush();

            mCodec.stop();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mCodec.reset();
            }

            mCodec.release();
            mCodec = null;
            Log.i("shurun", "mcodec释放");
        }
//        setAudioMode(this, AudioManager.MODE_NORMAL);

    }
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        // TODO Auto-generated method stub
        super.onConfigurationChanged(newConfig);
        Log.i("pingmu", "++++++++++++*");
        if (isScreenChange()) {
            Log.i("pingmu", "横屏");


            lp.height = screenWidth;
            float rate = 608 / (float) 448;
            Log.i("shurun2", rate + "");
            lp.width = (int) (screenWidth * rate);

            surfaceView.setLayoutParams(lp);
        } else {
            Log.i("pingmu", "shu屏");
            lp.width = screenWidth;
            lp.height = 448;
            float rate = 448 / (float) 608;
            Log.i("shurun2", rate + "");
            lp.height = (int) (screenWidth * rate);

            surfaceView.setLayoutParams(lp);
        }

    }

    public boolean isScreenChange() {
        Log.i("pingmu", "****");
        Configuration mConfiguration = this.getResources().getConfiguration(); // 获取设置的配置信息
        int ori = mConfiguration.orientation; // 获取屏幕方向

        if (ori == Configuration.ORIENTATION_LANDSCAPE) {

            // 横屏
            return true;
        } else if (ori == Configuration.ORIENTATION_PORTRAIT) {

            // 竖屏
            return false;
        }
        return false;
    }
}
